/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!				\file		CC_Err.h
 \date		june 2010
 \author		TNick

 \brief		Contains the definition of CC_Err class and related


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read ReadMe.txt and Licence.txt in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Settings to be exposed to the user:
 - AllowedTypes: what kind of elements shall be presented
 - ShwTy: how are going to be presented the messages

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
#define EM	1
#ifndef		__CC_ERR_INC__
#define		__CC_ERR_INC__
#ifdef		__cplusplus
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<QList>
#include	<QStringList>
#include	<QColor>
#include	<QVector>

/*  INCLUDES    ============================================================ */
//
//
//
//

namespace	CCERR	{
#define	SUCCEDED(r)		(r == CCERR::ERR_SUCCESS)

/* ------------------------------------------------------------------------- */
/// enumeration that asigns an error code for each possible error
enum		EERRORS
{
	ERR_SUCCESS = 0,	/**< standard way to tell that everything went ok*/
	ERR_USER,			/**< the user is to blame for the error */
	ERR_STATUS,			/**< the state of the object is not what was expected */
	ERR_BREAK,			/**< not really an error; caller sould break */
	ERR_MALLOC,			/**< memory allocation error */
	ERR_LIBRARY,		/**< a required library could not be loaded */
	ERR_GUI,			/**< GUI related error (generic) */
	ERR_IO,				/**< input / output error (files)*/
	ERR_CAPACITY,		/**< storage capacity exceded */


	ERR_COUNT			/**< tells last valid value; is not a real
	exit code*/
};
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/// enumeration that asigns numeric values to all possible contexts
/*
  WARNING!!!
  CC_Err::InitErrSys relies on a certain order for these items
 */
enum		ECTX
{
	CTX_APP = 0,		/**< application (generic) context */
	CTX_GUI,			/**< graphical user interface context */
	CTX_DRAWINT,		/**< drawing internals */
	CTX_PLUGINS,		/**< inside a plug-in (generic)
 or it's initialization */

	CTX_COUNT			/**< tells last valid value; is not a real
	context code*/
};
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/// describes the type of the entry
/*
  WARNING!!!
  CC_Err::InitErrSys relies on a certain order for these items
 */
enum	ETYPE	{
	EEMPTY = 0,	/**< unused array entry */

	EDEBUG_000 = 0x000001,	/**< debug message; only used for
  current development; none of the messages marked in
  this way shall end up in a release*/
	EDEBUG_IN = 0x000002,	/**< debug message; low level */
	EDEBUG_M = 0x000004,	/**< debug message; medium level */
	EDEBUG = 0x000008,		/**< debug message; high level */

	EWAR_IN = 0x000010,	/**< the execution will continue, but this is not
  what we had in mind when creating the element; this is an
  string that is meaningful for developer but has no
  value to the user */
	EWAR = 0x000020,		/**< the execution will continue, but this is not
  what we had in mind when creating the element; this is an
  string that is meaningful to the user and should be
  presented */

	EERR_IN = 0x000040,	/**< the execution will not continue; this is an
  string that is meaningful for developer but has no
  value to the user */
	EERR = 0x000080,		/**< the execution will not continue;
  this is an string that is intended to the user */


	EMAX = 0x0000FF			/**< for validation purposes */
};
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/// maps error types to consecutive integer values
enum	EIDX	{
	EIDX_DEBUG_000 = 0,
	EIDX_DEBUG_IN,
	EIDX_DEBUG_M,
	EIDX_DEBUG,
	EIDX_WAR_IN,
	EIDX_WAR,
	EIDX_ERR_IN,
	EIDX_ERR,
	EIDX_COUNT
};
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
/// enumeration that tells various ways of showing messages
enum		SHOW_TYPES
{
	SHW_NONE = 0,		/**< showing the messages is disabled at
	this time; cache the messages */
	SHW_DLG,				/**< pop-up dialog */
	SHW_OUT,			/**< at output panel; if it is hidden, it is
	auto-magically shown */
	SHW_OUTORMSG,		/**< at output panel if shown, otherwise show
	pop-up dialog */




	SHW_COUNT			/**< tells last valid value; is not a real
	show code*/
};
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/// describes a single entry in array
struct	EItem	{
	/// context of the message
	ECTX			ctx;
	/// the type of this message
	ETYPE			ty;
	/// the message itself
	QString			txt;
};
/* ========================================================================= */

}


class QTextEdit;

/// Class representing a corelation errror,
/**
*
*/
class	CC_Err {


	//
	//
	//
	//
	/*  DEFINITIONS    --------------------------------------------------------- */




	/*  DEFINITIONS    ========================================================= */
	//
	//
	//
	//
	/*  DATA    ---------------------------------------------------------------- */

	/// list of entries in this error structure
private:	QVector<CCERR::EItem>	Items;

	/// unique name used to identify an error structure
private:	unsigned			uId;



	/* 000000000000000000000000000000000000000000000000000000000000000 */
	/* static part; this is actually used in error management          */
	/* ............................................................... */
	/// counter used to generate unique ID's
private:	static unsigned				uErrCnt;
	/// chain of errors used when the system is in no position to show anything
private:	static QList<CC_Err*>		CacheErr;
	/// types of errors in cache
private:	static CCERR::ETYPE			CacheTypes;
	/// bit mask telling what type of messages are allowed for display
private:	static CCERR::ETYPE			AllowedTypes;
	/// value that tells how are we presenting the messages to the user
private:	static CCERR::SHOW_TYPES	ShwTy;
	/// array that holds names for contexts
private:	static QStringList			CtxNames;
	/// array that holds names for error types
private:	static QStringList			ETyNames;
	/// array that holds colors for error types
private:	static QList<QColor>		ETyColors;
	/* 000000000000000000000000000000000000000000000000000000000000000 */



	/*  DATA    ================================================================ */
	//
	//
	//
	//
	/*  FUNCTIONS    ----------------------------------------------------------- */

	/// constructor
public: CC_Err();
	/// destructor; will free resources;
public: virtual ~CC_Err();


	/// simply expose the number of items
public: inline int				count	(void)
	{ return Items.count();	}
	/// simply expose the id
public: inline unsigned int		Get_uId	(void)
	{ return uId;	}
	/// tell the context string for a particular index
public:	inline QString			Get_Context(unsigned i)
	{ return ContextName(Items[i].ctx); }
	/// tell the error type string for a particular type
public:	inline QString			Get_ErrType(unsigned i)
	{ return ErrTypeName(Items[i].ty); }
	/// tell the string for a particular index
public:	inline QString			Get_String(unsigned i)
	{
		return Items[i].txt;
	}
	/// tell if a particular index is allowed given the settings
public:	inline bool				Allowed(CCERR::ETYPE AlwTypes, unsigned i)
	{ return ((AlwTypes & Items[i].ty) != 0); }


	///	adds a new message to this error structure
public: void					Add		(
		CCERR::ETYPE		ty,		/**< the type of this error / message */
		CCERR::ECTX			ctx,	/**< context where this happened */
		QString				pErr	/**< message string */
		);
	/// shows this message according to current settings
public: void					Show	(void);


	///	shows this error as a message box
public: void					ShowMsgB	(void);
	/// shows this error in a rich edit control
public: void					ShowEdit	(
		CCERR::ETYPE		AlwTypes,
		QTextEdit*			OutTx,
		bool				bColPreserve = true
		);
	/// returns a single multiline string representing the error
public: QString					GetText		(void);
	/// duplicates an error structure internally
private: CC_Err*				DupErrI		(void);

	/* 000000000000000000000000000000000000000000000000000000000000000 */
	/* static part; this is actually used in error management          */
	/* ............................................................... */

	/// Initialization function for error system
public: static bool				InitErrSys	(void);

	/// Termination function for error system
public: static void				EndErrSys	(void);

	/// called just before initialization ends
public: static void				CruiseErrSys(void);

	/// function that gets a new ID
private: static unsigned		GetID		(void);

	/// flushes cached messages to an output medium decided by the settings
public: static void				FlushErrSys	(void);

	/// tell what kind of messages are allowed for display
public: inline static CCERR::ETYPE AllowedErrTypes	(void)
	{	return 	AllowedTypes; }

	/// change the kind of messages that are allowed for display
public: inline static bool		setAllowedErrTypes	(CCERR::ETYPE NewType)
	{
		if ((NewType < 0) || (NewType > CCERR::EMAX))
			return false;
		AllowedTypes = NewType;
		return true;
	}

	/// get the text associated with a context
public: inline static QString	ContextName(CCERR::ECTX idCtx)
	{
		if ((idCtx >= 0) && (idCtx < CCERR::CTX_COUNT))
			return CtxNames[idCtx];
		return QString();
	}

	/// get the index of an error based on error code
public: inline static unsigned	ErrTypeIndex(CCERR::ETYPE idETy)
	{
		/* a better approach would be to store the error type as
 consecutive numbers and do the shift via a macro; still, that
 requires run time shifts that are avoided by this method;*/
		switch	(idETy)	{
		case	CCERR::EDEBUG_000:		{ return CCERR::EIDX_DEBUG_000;}
		case	CCERR::EDEBUG_IN:		{ return CCERR::EIDX_DEBUG_IN;}
		case	CCERR::EDEBUG_M:		{ return CCERR::EIDX_DEBUG_M;}
		case	CCERR::EDEBUG:			{ return CCERR::EIDX_DEBUG;}
		case	CCERR::EWAR_IN:			{ return CCERR::EIDX_WAR_IN;}
		case	CCERR::EWAR:			{ return CCERR::EIDX_WAR;}
		case	CCERR::EERR_IN:			{ return CCERR::EIDX_ERR_IN;}
		case	CCERR::EERR:			{ return CCERR::EIDX_ERR;}
		default:						{ return 0xFFFF; }
		}
	};

	/// get the error code of an error based on index
public: inline static CCERR::ETYPE	ErrIndexType(unsigned uIdx)
	{
		return (CCERR::ETYPE)(1 << uIdx);
	};

	/// get the text associated with an error index
public: inline static QString	ErrTyTextFromIdx(unsigned uIdx)
	{
		if (uIdx < 0xFFFF)
			return ETyNames[uIdx];
		else
			return QString();
	}

	/// get the text associated with an error type
public: inline static QString	ErrTypeName(CCERR::ETYPE idETy)
	{
		return ErrTyTextFromIdx(ErrTypeIndex(idETy));
	};

	/// get the color associated with an error type
public: inline static QColor	ErrTypeColor(CCERR::ETYPE idETy)
	{
		unsigned	uIdx = ErrTypeIndex(idETy);
		if (uIdx < 0xFFFF)
			return ETyColors[uIdx];
		else
			return QColor("#000000");
	};

	/* 000000000000000000000000000000000000000000000000000000000000000 */






	/*  FUNCTIONS    =========================================================== */
	//
	//
	//
	//

};	/*	class	CC_Err	*/
//
//
//
//
#endif	//	__cplusplus
#endif	//	__CC_ERR_INC__
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
